﻿Public Class TypeLine : Implements IComparable(Of TypeLine)

    ''' <summary>
    ''' 边编号
    ''' </summary>
    ''' <remarks></remarks>
    Public sLineNo As String  '边编号
    ''' <summary>
    ''' 开始节点
    ''' </summary>
    ''' <remarks></remarks>
    Public startNode As TypeNode  '开始节点
    ''' <summary>
    ''' 结束节点
    ''' </summary>
    ''' <remarks></remarks>
    Public endNode As TypeNode   '结束节点  
    ''' <summary>
    ''' 斜率
    ''' </summary>
    ''' <remarks></remarks>
    Private rate As Double = 0  '夹角
    ''' <summary>
    ''' 相对斜率
    ''' </summary>
    ''' <remarks></remarks>
    Private RelaRate As Double = 0  '相对夹角
    Public Property LineNo() As String
        Get
            Return sLineNo
        End Get
        Set(ByVal value As String)
            sLineNo = value
        End Set
    End Property

    Public Property StartNodeName() As String
        Get
            If Me.startNode Is Nothing Then
                Return ""
            Else
                Return startNode.NodeName
            End If
        End Get
        Set(ByVal value As String)

        End Set
    End Property

    Public Property EndNodeName() As String
        Get
            If Me.endNode Is Nothing Then
                Return ""
            Else
                Return endNode.NodeName
            End If

        End Get
        Set(ByVal value As String)

        End Set
    End Property

    ''' <summary>
    ''' 设置相对斜率
    ''' </summary>
    ''' <param name="a"></param>
    ''' <param name="b"></param>
    ''' <remarks></remarks>
    Public Sub SetRelaRate(ByVal a As Double, ByVal b As Double)
        '设置和对比线的夹角
        Dim a1, b1, c1 As Double
        a1 = Math.Tan(a)
        b1 = Math.Tan(b)

        Me.RelaRate = Math.Atan(Math.Abs(a1 - b1) / (1 + a1 * b1)) / Math.PI * 180

        'Dim a1, b1, c1 As Double
        'a1 = Math.Abs(a) / Math.PI * 180
        'If a1 > 90 Then
        '    a1 = a1 - 90
        'End If

        'b1 = Math.Abs(b) / Math.PI * 180
        'If b1 > 90 Then
        '    b1 = b1 - 90
        'End If
        'c1 = a1 - b1
        'If c1 < 0 Then
        '    c1 = c1 + 90
        'End If
    End Sub
    Public Function GetRelaRate(Optional ByVal reCalc As Boolean = False) As Double
        GetRelaRate = Me.RelaRate
    End Function
    Public Function getRate(Optional ByVal reCalc As Boolean = False) As Double
        '获取斜率
        If Me.rate = 0 Or reCalc Then
            Me.rate = Math.Atan2((Me.startNode.latitude - Me.endNode.latitude), (Me.startNode.longitude - Me.endNode.longitude))
        End If
        getRate = Me.rate
    End Function

    ''' <summary>
    ''' 边类型
    ''' </summary>
    ''' <remarks></remarks>
    Private lineType As ClassConsManager.LineTypeEnum = ClassConsManager.LineTypeEnum.SIMPLE_LINE   '0 单边 1 复合边，2 环边
    Private innerLines() As TypeLine '内部边，如果是环边类型 
    Public Function getInnerLines() As TypeLine()
        getInnerLines = Me.innerLines
    End Function


    Public NodeList() As TypeNode '复合边节点列表
    Public Function getInnerNodes() As TypeNode()
        getInnerNodes = Me.NodeList
    End Function
    Public Function getLineType() As ClassConsManager.LineTypeEnum
        getLineType = lineType
    End Function
    Public Function isCombinLine() As Boolean
        If lineType = ClassConsManager.LineTypeEnum.SIMPLE_LINE Then
            isCombinLine = False
        Else
            isCombinLine = True
        End If
    End Function
    Public Sub setCombinLine(ByVal ptype As ClassConsManager.LineTypeEnum)
        lineType = ptype
    End Sub
    Private loger As IClassLog = New IClassLog '日子记录员
    Private bDeleteFlag As Boolean    '删除标志
    Public Function isDelete() As Boolean '删除标志
        isDelete = bDeleteFlag
    End Function
    Public Sub setDelete(ByVal boolDelete As Boolean)  '删除标志
        bDeleteFlag = boolDelete
    End Sub
    Private bNull As Boolean  '空标志
    Public Function isNull() As Boolean '空标志
        isNull = bNull
    End Function
    Public Sub setNull(ByVal boolNull As Boolean)  '空标志
        bNull = boolNull
    End Sub
    Public Sub addInnerNode(ByRef pNode As TypeNode)
        '插入内部节点
        Dim innerNodeCount As Integer = UBound(NodeList)
        ReDim Preserve NodeList(innerNodeCount + 1)
        NodeList(innerNodeCount) = pNode
    End Sub
    Private bSearched As Boolean = False '是否搜索过标志
    Public Function isSearched() As Boolean
        isSearched = bSearched
    End Function
    Public Function SetSearched(Optional ByVal pSearched As Boolean = True) As Boolean
        bSearched = pSearched
    End Function
    Public Sub addInnerLines(ByRef pLine As TypeLine)
        '添加内部边
        If innerLines Is Nothing Then
            ReDim innerLines(0)
        End If
        '头一个边
        If innerLines(0) Is Nothing Then
            If pLine.lineType = ClassConsManager.LineTypeEnum.RING_LINE Then
                '环线，将环线中的线，添加到内部边表中
                Dim i As Integer = 0
                For Each tmpLine As TypeLine In pLine.getInnerLines
                    If Not tmpLine Is Nothing Then
                        '如果内部表不是空对象，将内部表转入新的内部表中
                        innerLines(i) = tmpLine
                        i = i + 1
                    End If
                Next
            Else
                innerLines(0) = pLine
            End If
            Exit Sub
        End If

        If pLine.getLineType = ClassConsManager.LineTypeEnum.RING_LINE Then
            '2个节点间，不能存在2个以上的环线边，所以不存在这种情况，如果有，系统存在问题
            loger.log("2个节点间，不能存在2个以上的环线边,不进行处理", ClassConsManager.LOG_LEVEL_CRITICAL)

            '环线，将环线中的线，添加到内部边表中
            'Dim i As Integer = innerLines.GetLength(0)
            'ReDim Preserve innerLines(innerLines.GetLength(0) + pLine.getInnerLines.GetLength(0))
            'For Each tmpLine As TypeLine In pLine.getInnerLines
            '    If Not tmpLine Is Nothing Then
            '        '如果内部表不是空对象，将内部表转入新的内部表中
            '        innerLines(i) = tmpLine
            '        i = i + 1
            '    End If
            'Next
        Else
            '添加内部边    
            ReDim Preserve innerLines(innerLines.GetLength(0))
            innerLines(innerLines.GetLength(0) - 1) = pLine
        End If
    End Sub


    Public Function reverseLine(ByRef pLine As TypeLine) As TypeLine
        '将一条线路翻转
        Dim tmpLine As TypeLine
        Dim tmpStartNode, tmpEndNode, tmpNodeList(), tmpNode As TypeNode

        tmpStartNode = pLine.endNode
        tmpEndNode = pLine.startNode
        tmpNodeList = pLine.getInnerNodes
        If pLine.isCombinLine = True Then
            '是符合线，需要将内部的节点序号翻转
            For i = 0 To (UBound(tmpNodeList) + 1) / 2
                '对节点中的数据进行换方向
                tmpNode = tmpNodeList(i)
                tmpNodeList(i) = tmpNodeList(UBound(tmpNodeList) - i)
                tmpNodeList(UBound(tmpNodeList) - i) = tmpNode
            Next
            '后面需要继续处理高差等其他信息

        End If



        tmpLine = New TypeLine(tmpStartNode, tmpEndNode, tmpNodeList)
        reverseLine = tmpLine
    End Function
    Public Sub reverseLine()
        '将一条线路翻转
        Dim tmpStartNode, tmpEndNode, tmpNodeList(), tmpNode As TypeNode
        tmpStartNode = Me.endNode
        tmpEndNode = Me.startNode
        tmpNodeList = Me.getInnerNodes
        If Me.getLineType = ClassConsManager.LineTypeEnum.COMBIN_LINE Then
            '是符合线，需要将内部的节点序号翻转
            For i = 0 To (UBound(tmpNodeList) + 1) / 2
                '对节点中的数据进行换方向
                tmpNode = tmpNodeList(i)
                tmpNodeList(i) = tmpNodeList(UBound(tmpNodeList) - i)
                tmpNodeList(UBound(tmpNodeList) - i) = tmpNode
            Next
            '后面需要继续处理高差等其他信息
        End If

        Me.startNode = tmpStartNode
        Me.endNode = tmpEndNode
        Me.NodeList = tmpNodeList
        Me.getRate(True)
    End Sub

    Public Function combinLine(ByRef tmpLine1 As TypeLine, ByRef tmpLine2 As TypeLine) As TypeLine
        Dim isSelfRing As Boolean = False
        combinLine = Nothing

        '将2个线段合并为一个线段
        '调整线条方向，使第一条线的结束点为第二条线的开始节点
        If tmpLine1.startNode.sNodeNo = tmpLine2.startNode.sNodeNo Then
            '两条线的开始节点相同,需要将一条线导致。
            '第1条线反转
            If tmpLine1.endNode.sNodeNo = tmpLine2.endNode.sNodeNo Then
                '2条线的两端节点一致，构成自由环，生成环
                isSelfRing = True
            Else
                tmpLine1.reverseLine()
            End If
        ElseIf tmpLine1.startNode.sNodeNo = tmpLine2.endNode.sNodeNo Then
            '第一条线的开始节点是第二条线的结束节点，调换一下线1和线2 的位置
            If tmpLine1.endNode.sNodeNo = tmpLine2.startNode.sNodeNo Then
                '2条线的两端节点一致，构成自由环，生成环
                isSelfRing = True
            Else
                Dim tmpline As TypeLine
                tmpline = tmpLine1
                tmpLine1 = tmpLine2
                tmpLine2 = tmpline
                tmpline = Nothing
            End If
        ElseIf tmpLine1.endNode.sNodeNo = tmpLine2.endNode.sNodeNo Then
            '第一条线的结束节点是第二条线的结束节点，第二条线换方向
            If tmpLine1.startNode.sNodeNo = tmpLine2.startNode.sNodeNo Then
                '2条线的两端节点一致，构成自由环，生成环
                isSelfRing = True
            Else
                tmpLine2.reverseLine()
            End If

        ElseIf tmpLine1.endNode.sNodeNo = tmpLine2.startNode.sNodeNo Then
            '符合规律，不换方案
            If tmpLine1.startNode.sNodeNo = tmpLine2.endNode.sNodeNo Then
                '2条线的两端节点一致，构成自由环，生成环
                isSelfRing = True
            Else

            End If
        Else
            '两条线没有共同节点，进行提示
            loger.log("拼接的两条线没有共同节点" & tmpLine1.getString & "" & tmpLine2.getString, ClassConsManager.LOG_LEVEL_ERROR)
        End If

        If isSelfRing = True Then
            '已经可以组成一个环，新建一个环

        Else
            '构建复合线
            Dim newStartNode, newEndNode, innerNodes() As TypeNode
            Dim innerNodeCount As Integer = 0
            Dim startPosision As Integer = 0
            newStartNode = tmpLine1.startNode
            newEndNode = tmpLine2.endNode

            '第一条线
            If tmpLine1.isCombinLine = True Then
                '是复合线，需要取出内部节点
                innerNodeCount = innerNodeCount + tmpLine1.getInnerNodes().GetLength(0)
                ReDim Preserve innerNodes(innerNodeCount)
                For Each tmpNode As TypeNode In tmpLine1.getInnerNodes
                    innerNodes(startPosision) = tmpNode
                    startPosision = startPosision + 1
                Next
            End If

            '中间节点

            ReDim Preserve innerNodes(innerNodeCount) '建立内部节点数组
            innerNodes(startPosision) = tmpLine1.endNode '添加中间节点
            innerNodeCount = innerNodeCount + 1
            startPosision = startPosision + 1

            '第二条线
            If tmpLine2.isCombinLine = True Then
                '是复合线，需要取出内部节点
                innerNodeCount = innerNodeCount + tmpLine2.getInnerNodes().GetLength(0)
                ReDim Preserve innerNodes(innerNodeCount)
                For Each tmpNode As TypeNode In tmpLine2.getInnerNodes
                    innerNodes(startPosision) = tmpNode
                    startPosision = startPosision + 1
                Next
            End If

            ReDim Preserve innerNodes(startPosision - 1)

            '建立新的线条
            combinLine = New TypeLine(newStartNode, newEndNode, innerNodes)
            combinLine.setCombinLine(True)
        End If

    End Function

    '构造函数
    Public Sub New(ByVal pStartNode As TypeNode, ByVal pEndNode As TypeNode, ByVal pNodeList() As TypeNode)
        Me.startNode = pStartNode
        Me.endNode = pEndNode
        Me.NodeList = pNodeList
    End Sub

    Public Sub New(ByVal pStartNode As TypeNode, ByVal pEndNode As TypeNode, ByVal pLineType As ClassConsManager.LineTypeEnum)
        Me.startNode = pStartNode
        Me.endNode = pEndNode
        Me.lineType = pLineType
    End Sub

    '构造函数
    Public Sub New()

    End Sub


    Public Function getString() As String
        '打印线信息
        Dim str As String
        str = sLineNo
        str = str & "," & Me.startNode.sNodeNo & "," & Me.endNode.sNodeNo & "," & Me.lineType
        getString = str
    End Function

    Public Function CompareTo(ByVal x As TypeLine) As Integer Implements IComparable(Of ICloseCircle.TypeLine).CompareTo
        '    Compare = x.rate.CompareTo(y.rate)
        If x.startNode.Equals(Me.startNode) Then
            CompareTo = x.endNode.CompareTo(Me.endNode)

        Else
            CompareTo = x.startNode.CompareTo(Me.startNode)
        End If

    End Function
End Class
